/**
 *     @file ctf.h
 *     @brief Common Test Framework
 *     This is a simple unit test framework used for my compiler project
 *
 *     @defgroup ctf Common Test Framework
 *     The module for unit test.
 *     @{
 */

#ifndef __CTF_H__
#define __CTF_H__

#ifndef bool
#define bool char
#define TRUE 1
#define FALSE 0
#endif

#include "log.h"
#include <stdio.h>

#define MAX_STR 255

/// return type of CTF
#define RESULT_OK        1

/// return type of CTF
#define RESULT_ERROR     0

/// test case type
typedef struct ctf_testcase_ *ctf_testcase;

/// test suit type
typedef struct ctf_testsuit_ *ctf_testsuit;

/// test case callback function pointer type
typedef int (*tc_func)(ctf_testcase tc);

/// callback function pointer type used in CTF
typedef void (*fix_func)();

struct ctf_testcase_
{
    ctf_testcase next, prev;
    char     name[MAX_STR+1];
    tc_func func;
    int     failed;
};

struct ctf_testsuit_
{
    char name[MAX_STR+1];
    ctf_testcase tcFirst, tcLast;
    int     failed;
    int     ran;
    fix_func setup;
    fix_func teardown;

    ctf_testsuit next, prev;
};

typedef struct ctf_test_
{
    char name[MAX_STR+1];
    ctf_testsuit tsFirst, tsLast;
} *ctf_test;

/** 
 * @brief Initialize the CTF
 *
 * This function should be called before all other CTF functions. It will 
 * initialize the CTF environment and do some other work.
 * @param desc Description for the test
 * @param logname The file name of the test log
 */
void ctf_begin(char* desc, char* logname);

/// Call this function at the end of the test
void ctf_end();

/// Begin the test suit.
void ctf_run();

/**
 * @brief Create a test suit
 *
 * @param name The name of the test suit
 * @param steup Function pointer used for setup the test suit
 * @param teardown Function pointer whitch will be call at the end of the test 
 * suit
 * @return A new test suit pointer
 */
ctf_testsuit ctf_ts_init(char* name, fix_func setup, fix_func teardown);

/**
 * @brief Add a test function to a test suit
 *
 * @param ts test suit pointer
 * @param func function pointer used to run the actual test
 * @param name the name for this test function
 */
void ctf_tc_add(char* name, ctf_testsuit ts, tc_func func);

bool _assert_(char* msg, int cond, int line, char* filename);

/// @brief assert function of CTF
#define ctf_assert(msg, cond) _assert_(msg, cond, __LINE__, __FILE__)

#define ctf_assert_cmd(msg, cond, cmd_fail) \
    if( !_assert_(msg, cond, __LINE__, __FILE__) ) \
        { cmd_fail; }

#define ctf_assert_msg(msg, cond, msg_fail) \
    if( !_assert_(msg, cond, __LINE__, __FILE__) )  \
        LOG_CONTENT(msg_fail, RAYLOG_HIGH)

/// @brief macro for test case function header
#define TEST(x, y) int x##_##y(ctf_testcase tc)
#define SETUP(x) void x##_setup()
#define DESTROY(x) void x##_destroy()
#endif

///@}

